/*********************************************************************
 *
 *              Application Programming Interface (API)
 *                     for COM-R04-S01b Module
 *
 *********************************************************************
 * FileName:        com_r04_s01b.c
 * Dependencies:    platform.h
 * Processor:       processor independent
 * Complier:        compiler independent
 * Company:         Budapest University of Technology and Economics
 * 					Department of Measurement and Information Systems
 *
 * note:
 *	General API for the COM-R04-S01b Mitmot module. This API use the
 * 	Mitmote BUS functions specified by the mcu API.
 *
 * Standard COM-R04-S01b is configured to 433MHz operation with 10MHz
 * xtal using a 12pF load. Also as typically is FIFO enabled operation
 * only mitmot GPIO13 and GPIO14 is used in addition to the SPI pins.
 * GPIO13 is for SPI slave select, and GPIO14 for the Interrupt signal
 * (nIRQ)
 *
 * Author               Date    Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Balazs Scherer     10/06/05   Original
 ********************************************************************/

#include "com_r04_s01b.h"
#include "platform.h"

/********************************************************************/
/*************        Internal functions       **********************/
/********************************************************************/

unsigned short update_crc(unsigned short crc, unsigned char *buf, int len);
unsigned short crc(unsigned char *buf, int len);

/********************************************************************/
/*************             Globals             **********************/
/********************************************************************/

unsigned char transfer_setting = 0x00;

/*********************************************************************/
/*********************************************************************/
/**********          Inicialisation, controll	      ****************/
/*********************************************************************/
/*********************************************************************/

/*********************************************************************
 * Function: 	  void com_r04_s01__Init_433 (void)
 *
 * PreCondition:  none
 *
 * Input:         unsigned int sub_frequency: The sub frequency band for RF
 * 					communication.
 * 				  unsigned char baseband_bw: Select the baseband BW
 * 					between 67kHz and 400 kHz
 * 				  unsigned char deviation: FSK deviation between 15kHz to 240 kHz
 * 				  unsigned char power: Relative output power. The maximum is about 8dBm
 * 				  unsigned char data_rate: setting the communication data rate
 *
 * Output:        none
 *
 * Side Effects:  1, Inicialisation of the SPI interface, and the
 * 				  	 GPIO pins used by the com-r04 module
 * 				  2, Setting the Configuration setting to 433 MHz
 * 					 main band, 12pF load and enabling Tx data register
 * 					 Rx FIFO.
 * 				  3, Setting up the sub bands to the 433.050 - 434.790 MHz
 * 					 ISM bands using the com_r04_s01__Set_Sub_Frequency.
 * 				  4, Enabling the synthesier and the oscillator in the
 * 					 power management register
 * 				  5, Setting baseband BW with com_r04_s01__Set_Baseband_BW
 * 				  6, Setting the deviation with com_r04_s01__Set_Deviation
 * 				  7, Setting the Relative output power with
 * 					 com_r04_s01__Set_Relative_Output_power
 * 				  8, Setting the data rate with com_r04_s01__Set_Data_rate
 *
 * Overview:      Call the appropriate MCU api functions for
 * 				  PIN direction and SPI inicialisation.
 * 				  Then configurating the RF communication with the appropirate
 * 				  API functions
 *
 * Note:          USE PRE DEFINED PARAMETERS
 ********************************************************************/

void com_r04_s01__Init_433(unsigned int sub_frequency,
		unsigned char baseband_bw, unsigned char deviation,
		unsigned char power, unsigned char data_rate) {
	unsigned char data1, data2;

	/************/
	GPIO_13_DIR_OUTPUT();
	GPIO_14_DIR_INPUT();

#if ARM_LPC2106
	SPI_Init(0, 0, 0, 100);
#elif AVR_ATMEGA128
	SPI_Init(0,0,0,4);
#endif

	// Configuration Setting command
	GPIO_13_CLEAR();
	SPI_byte(0x80, &data1);
	SPI_byte(0xD7, &data2); // enables the internal data register, rx fifo, 433 MHz, 12 pF
	GPIO_13_SET();

	// Configuration Setting command again experiences shows that it should be done twice
	GPIO_13_CLEAR();
	SPI_byte(0x80, &data1);
	SPI_byte(0xD7, &data2); // enables the internal data register, rx fifo, 433 MHz, 12 pF
	GPIO_13_SET();

	// Sub frequencies
	com_r04_s01__Set_Sub_Frequency(sub_frequency);

	// Power management command
	GPIO_13_CLEAR();
	SPI_byte(0x82, &data1);
	SPI_byte(0x18, &data2);
	GPIO_13_SET(); // syntheser, oscillator on

	// Setting baseband BW
	com_r04_s01__Set_Baseband_BW(baseband_bw);

	// Transmiter Controll command
	com_r04_s01__Set_Deviation(deviation);
	com_r04_s01__Set_Relative_Output_power(power);

	// Transmiter Controll command
	com_r04_s01__Set_Data_rate(data_rate);

	// dummy status read for power on reset acknowledgement
	com_r04_s01__Read_Status();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Set_Sub_Frequency (unsigned int frequency)
 *
 * PreCondition:  SPI, and GPIO inicialisation
 *
 * Input:         unsigned int frequency: The sub frequency band for RF
 * 					communication. Do not set operating frequency outside
 * 					the ISM bands. USE THE PRE DEFINED SUB BANDS.
 * 					(SUB_BAND_433_1_MHz for example)
 *
 * Output:        none
 *
 * Side Effects:  Setting the Frequency register in the IA4420.
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          Do not set operating frequency outside the ISM bands.
 * 				  USE THE PRE DEFINED SUB BANDS. (SUB_BAND_433_1_MHz for example)
 ********************************************************************/
void com_r04_s01__Set_Sub_Frequency(unsigned int frequency) {
	unsigned char d1, d2, data;

	// Frequency Setting command
	d1 = (unsigned char) ((frequency & 0xFF00) >> 8);
	d2 = (unsigned char) (frequency & 0x00FF);

	GPIO_13_CLEAR();
	SPI_byte(d1, &data);
	SPI_byte(d2, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Set_Baseband_BW (unsigned char baseband)
 *
 * PreCondition:  SPI, and GPIO inicialisation
 *
 * Input:         unsigned char baseband: Select the baseband BW
 * 					between 67kHz and 400 kHz
 *
 * Output:        none
 *
 * Side Effects:  Setting the Baseband BW for receiver part and
 * 				  also setting the LNA max, VDI output, DRSSI -103 dBm
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          Use the pre defined values like BASEBAND_BW_400_kHz
 ********************************************************************/
void com_r04_s01__Set_Baseband_BW(unsigned char baseband) {
	unsigned char data;

	// Setting the baseband in Receiver controll

	GPIO_13_CLEAR();
	SPI_byte(0x96, &data);
	SPI_byte(baseband, &data); // Setting LNA max, VDI output, DRSSI -103 dBm
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Set_Deviation (unsigned char deviation)
 *
 * PreCondition:  SPI, and GPIO inicialisation
 *
 * Input:         unsigned char deviation: FSK deviation between 15kHz to 240 kHz
 *
 * Output:        none
 *
 * Side Effects:  Setting the FSK deviation between 15kHz to 240 kHz
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          Use pre defined values like FSK_DEVIATION_90_kHz
 ********************************************************************/
void com_r04_s01__Set_Deviation(unsigned char deviation) {
	unsigned char data;

	// Setting the deviation the bits 0 to 3 contains the PA values
	// we keeping them
	transfer_setting = ((transfer_setting & 0x0F) | deviation);

	GPIO_13_CLEAR();
	SPI_byte(0x98, &data);
	SPI_byte(transfer_setting, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Set_Relative_Output_power (unsigned char power)
 *
 * PreCondition:  SPI, and GPIO inicialisation
 *
 * Input:         unsigned char power: Relative output power. The maximum is
 * 					about 8dBm
 *
 * Output:        none
 *
 * Side Effects:  Setting the relative output power
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          Use pre defined values like OUTPUT_POWER_MAX_minus_6dB
 ********************************************************************/
void com_r04_s01__Set_Relative_Output_power(unsigned char power) {
	unsigned char data;

	// Setting the deviation the bits 4 to 7 contains the deviation
	// values, therefore we keeping them
	transfer_setting = ((transfer_setting & 0xF0) | power);

	GPIO_13_CLEAR();
	SPI_byte(0x98, &data);
	SPI_byte(transfer_setting, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Set_Data_rate (unsigned char data_rate)
 *
 * PreCondition:  SPI, and GPIO inicialisation
 *
 * Input:         unsigned char data_rate: setting the communication data rate
 *
 * Output:        none
 *
 * Side Effects:  Setting the data rate register
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          Use pre defined values like DATA_RATE_9600_bps
 ********************************************************************/
void com_r04_s01__Set_Data_rate(unsigned char data_rate) {
	unsigned char data;

	// Data rate register setting

	GPIO_13_CLEAR();
	SPI_byte(0xC6, &data);
	SPI_byte(data_rate, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  unsigned int com_r04_s01__Read_Status (void)
 *
 * PreCondition:  SPI, and GPIO inicialisation
 *
 * Input:         none
 *
 * Output:        The 16bit status word of the IA4420
 *
 * Side Effects:  Reading the RF chip's status
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          none
 ********************************************************************/

unsigned int com_r04_s01__Read_Status(void) {
	unsigned char data1, data2;
	unsigned int status;

	GPIO_13_CLEAR();

	//  Read status
	SPI_byte(0x00, &data1);
	SPI_byte(0x00, &data2);

	GPIO_13_SET();

	status = (data1 << 8) + data2;
	return status;
}

/*********************************************************************/
/*********************************************************************/
/*****************          Transmitting	          ****************/
/*********************************************************************/
/*********************************************************************/

/*********************************************************************
 * Function: 	  void com_r04_s01__Transmitter_Disable (void)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         none
 *
 * Output:        none
 *
 * Side Effects:  Disabling the transmitter. The synthesier and the oscillator
 * 				  remains enabled.
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          Always disable transmitter after sending a packet, or the
 * 				  radio remains active and sends 0-s.
 ********************************************************************/

void com_r04_s01__Transmitter_Disable(void) {
	unsigned char data;

	// Power management command
	GPIO_13_CLEAR();
	SPI_byte(0x82, &data);
	SPI_byte(0x18, &data); // syntheser, oscillator on
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Start_Transmitting (void)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         none
 *
 * Output:        none
 *
 * Side Effects:  Disabling and then enabling the transmitter which starts
 * 				  transmitting the value in the TX register
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          none
 ********************************************************************/

void com_r04_s01__Start_Transmitting(void) {
	unsigned char data;

	// Power management command
	GPIO_13_CLEAR();
	SPI_byte(0x82, &data);
	SPI_byte(0x18, &data); // disable transmitter
	GPIO_13_SET();

	// Power management command
	GPIO_13_CLEAR();
	SPI_byte(0x82, &data);
	SPI_byte(0x38, &data); // enable transmitter
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Write_Transmit_data (unsigned char d)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         unsigned char d: 8bit data to transmit
 *
 * Output:        none
 *
 * Side Effects:  Writing the data to the transmit register
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          none
 ********************************************************************/

void com_r04_s01__Write_Transmit_data(unsigned char d) {
	unsigned char data;

	// Transmit register write command
	GPIO_13_CLEAR();
	SPI_byte(0xB8, &data);
	SPI_byte(d, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Send_Packet (unsigned char* buffer, unsigned short int length)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         unsigned char* buffer: pointer to the data to send
 * 				  unsigned short int length: the length of the data
 *
 * Output:        none
 *
 * Side Effects:  Sending the data using the RF link
 *
 * Overview:      1, Inicializating the Tx reg with 0xAA preamble
 * 				  2, Start the transmitting. com_r04_s01__Start_Transmitting()
 * 				  3, Sending 7 other 0xAA as preamble
 * 				  4, Sending the 0x2DD4 as syncron pattern
 * 				  5, Sending the packet length
 * 				  6, Sending the data
 * 				  7, Calculating and sending the CRC
 * 				  8, Disabling the transducer
 *
 * Note:          This function is a blocking one. After every byte send
 * 				  we are waiting for the TX register empty IT signal, and
 * 				  therefore if radio hardware error then the program
 * 				  execution is halted.
 ********************************************************************/

void com_r04_s01__Send_Packet(unsigned char* buffer, unsigned short int length) {
	unsigned int i, status1;
	unsigned short int crc_value;

	/*** Start transmitting ***/
	com_r04_s01__Write_Transmit_data(0xAA);
	com_r04_s01__Start_Transmitting();

	/*** Sending preamble ***/
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xAA);

	/*** Sending syncron pattern ***/
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0x2D);
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0xD4);

	/*** Sending packet length ***/
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(((length & 0xFF00) >> 8));
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(length & 0x00FF);

	/*** Sending data ***/
	for (i = 0; i < length; i++) {
		while (GPIO_14_GET_VALUE());
		status1 = com_r04_s01__Read_Status();
		com_r04_s01__Write_Transmit_data(buffer[i]);
	}

	/*** Sending CRC ***/
	crc_value = crc(buffer, length);

	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(((crc_value & 0xFF00) >> 8));
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(crc_value & 0x00FF);

	/*** Disabling the transmitter ***/
	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Write_Transmit_data(0x00);

	while (GPIO_14_GET_VALUE());
	status1 = com_r04_s01__Read_Status();
	com_r04_s01__Transmitter_Disable();
}

/*********************************************************************/
/*********************************************************************/
/*******************          Receiving	              ****************/
/*********************************************************************/
/*********************************************************************/

/*********************************************************************
 * Function: 	  void com_r04_s01__Enable_Receiver (void)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         none
 *
 * Output:        none
 *
 * Side Effects:  Enabling the receiver path by enabling the receiver and
 * 				  baseband
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          none
 ********************************************************************/

void com_r04_s01__Enable_Receiver(void) {
	unsigned char data;
	// Power management command

	GPIO_13_CLEAR();
	SPI_byte(0x82, &data);
	SPI_byte(0xD8, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  com_r04_s01__Disable_Receiver (void)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         none
 *
 * Output:        none
 *
 * Side Effects:  Disabling the receiver path
 *
 * Overview:      Uses MCU api for SPI communication.
 *
 * Note:          none
 ********************************************************************/

void com_r04_s01__Disable_Receiver(void) {
	unsigned char data;
	// Power management command

	GPIO_13_CLEAR();
	SPI_byte(0x82, &data);
	SPI_byte(0x18, &data);
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  void com_r04_s01__Start_Receiving (void)
 *
 * PreCondition:  com_r04_s01__Init_433, com_r04_s01__Enable_Receiver
 *
 * Input:         none
 *
 * Output:        none
 *
 * Side Effects:  Disabling and then enabling the Synchron pattern recognition
 *
 * Overview:      Uses MCU api for SPI communication. For configurating the
 * 				  FIFO buffer register
 *
 * Note:          After enabling the synchron pattern recognition the IA4420
 * 				  will notify us if a 0x2DD4 is received by pulling down the
 * 				  nIRQ signal.
 ********************************************************************/

void com_r04_s01__Start_Receiving(void) {
	unsigned char data1, data2;

	// FIFO buffer
	GPIO_13_CLEAR();
	SPI_byte(0xCA, &data1);
	SPI_byte(0x80, &data2); // Synchron pattern, disable patern recog
	GPIO_13_SET();

	// FIFO buffer
	GPIO_13_CLEAR();
	SPI_byte(0xCA, &data1);
	SPI_byte(0x82, &data2); // Synchron pattern, enable patern recog
	GPIO_13_SET();

}

/*********************************************************************
 * Function: 	  unsigned char com_r04_s01__Read_FIFO (void)
 *
 * PreCondition:  com_r04_s01__Init_433, com_r04_s01__Enable_Receiver,
 * 				  com_r04_s01__Start_Receiving
 *
 * Input:         none
 *
 * Output:        unsigned char: 8 bit data readed from the receive FIFO
 *
 * Side Effects:  Reading 8 bit data from the FIFO
 *
 * Overview:      Uses MCU api for SPI communication for reading the FIFO
 *
 *
 * Note:          none
 ********************************************************************/

unsigned char com_r04_s01__Read_FIFO(void) {
	unsigned char data1, data2;

	// FIFO buffer
	GPIO_13_CLEAR();
	SPI_byte(0xB0, &data1);
	SPI_byte(0x00, &data2); // Pmax
	GPIO_13_SET();

	return data2;
}

/*********************************************************************
 * Function: 	  unsigned char com_r04_s01__Receiving_Packet (unsigned char* buffer, unsigned short int* length)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         unsigned char* buffer: pointer for the incomming data
 * 				  unsigned short int* length: the maximum length of the incomming packet
 *
 * Output:        unsigned char: COM_R04_S01__ERROR if the length of the incomming packet is
 * 								 greater than unsigned short int* length parameter. Or the
 * 								 received packet contains a CRC error.
 * 								 COM_R04_S01__NOERROR if the packet is received correctly
 *
 * 				  unsigned short int* length: the length of the received packet
 *
 * Side Effects:  Waiting for a packet to receive
 *
 * Overview:      1, Enabling the receiver path with com_r04_s01__Enable_Receiver()
 * 				  2, Starting the synchron patter recognition with com_r04_s01__Start_Receiving()
 * 				  3, Waiting for the synchron pattern THIS IS A BLOCKING PART WITHOUT A TIME LIMIT
 * 				  4, reading and comparing the length of the packet with the incomming length
 * 					 parameter. If the received length is greater than the specified maximum, then
 * 					 aborting the packet receive and signaling an error
 * 				  5, receiving the packet
 * 				  6, receiving and checking the CRC. If the CRC is not correct then
 * 					 aborting the packet receive and signaling an error
 * 				  7, Packed receive finished. Disabling the receiver
 *
 * Note:          This is a blocking function and waits until a packet is received
 ********************************************************************/
unsigned char com_r04_s01__Receiving_Packet(unsigned char* buffer,
		unsigned short int* length) {
	unsigned char d1, d2;
	unsigned int len, i, status;
	unsigned short int crc_value_r, crc_value_c;

	com_r04_s01__Enable_Receiver();
	com_r04_s01__Start_Receiving();

	/*** waiting for syncron pattern ***/
	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d1 = com_r04_s01__Read_FIFO();

	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d2 = com_r04_s01__Read_FIFO();

	len = (d1 << 8) + d2;

	if (len > *length) {
		com_r04_s01__Disable_Receiver();
		return COM_R04_S01__ERROR;
	}

	*length = len;

	for (i = 0; i < len; i++) {
		while (GPIO_14_GET_VALUE());
		status = com_r04_s01__Read_Status();
		buffer[i] = com_r04_s01__Read_FIFO();
	}

	/*** Receiving CRC ***/
	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d1 = com_r04_s01__Read_FIFO();

	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d2 = com_r04_s01__Read_FIFO();

	crc_value_r = (d1 << 8) + d2;
	crc_value_c = crc(buffer, len);

	if (crc_value_r != crc_value_c) {
		com_r04_s01__Disable_Receiver();
		return COM_R04_S01__ERROR;
	}

	com_r04_s01__Disable_Receiver();

	return COM_R04_S01__NOERROR;

}

/*********************************************************************
 * Function: 	  unsigned char com_r04_s01__Receiving_Packet_with_timeout (unsigned char* buffer, unsigned short int* length, unsigned short int timeout)
 *
 * PreCondition:  com_r04_s01__Init_433
 *
 * Input:         unsigned char* buffer: pointer for the incomming data
 * 				  unsigned short int* length: the maximum length of the incomming packet
 *				  unsigned short int timeout: Timeout in ms. (This is not a precise timeout only an approximetry one)
 *
 * Output:        unsigned char: COM_R04_S01__ERROR if the length of the incomming packet is
 * 								 greater than unsigned short int* length parameter. Or the
 * 								 received packet contains a CRC error.
 *								 COM_R04_S01__TIMEOUT if timeout occured
 * 								 COM_R04_S01__NOERROR if the packet is received correctly
 *
 * 				  unsigned short int* length: the length of the received packet
 *
 * Side Effects:  Waiting for a packet to receive with timeout
 *
 * Overview:      1, Enabling the receiver path with com_r04_s01__Enable_Receiver()
 * 				  2, Starting the synchron patter recognition with com_r04_s01__Start_Receiving()
 * 				  3, Waiting for the synchron pattern or timeout
 * 				  4, reading and comparing the length of the packet with the incomming length
 * 					 parameter. If the received length is greater than the specified maximum, then
 * 					 aborting the packet receive and signaling an error
 * 				  5, receiving the packet
 * 				  6, receiving and checking the CRC. If the CRC is not correct then
 * 					 aborting the packet receive and signaling an error
 * 				  7, Packed receive finished. Disabling the receiver
 *
 * Note:          This is a blocking function and waits until a packet is received or timeout.
 ********************************************************************/

unsigned char com_r04_s01__Receiving_Packet_with_timeout(unsigned char* buffer,
		unsigned short int* length, unsigned short int timeout) {
	unsigned char d1, d2;
	unsigned int len, i, status, k;
	unsigned int timeout_counter;

	unsigned short int crc_value_r, crc_value_c;

	timeout_counter = timeout * 10; /********************************************************/
	com_r04_s01__Enable_Receiver();
	com_r04_s01__Start_Receiving();
	status = com_r04_s01__Read_Status();

	/*** waiting for syncron pattern, or time out ***/

	while (GPIO_14_GET_VALUE() && timeout_counter) /**************************************/
	{
		timeout_counter--;
#if ARM_LPC2106
		//hal_delay_us(2);
		for (k = 0; k < CYGNUM_HAL_CPU_SPEED / 1000000 * 2; k++)
			;
#elif AVR_ATMEGA128
		_delay_us(2);
#endif
	}

	if (timeout_counter <= 0) {
		//		printf("Timeout = %d",timeout_counter);
		return COM_R04_S01__TIMEOUT;
	}

	//	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d1 = com_r04_s01__Read_FIFO();

	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d2 = com_r04_s01__Read_FIFO();

	len = (d1 << 8) + d2;

	if (len > *length)
		return COM_R04_S01__ERROR;

	*length = len;

	for (i = 0; i < len; i++) {
		while (GPIO_14_GET_VALUE());
		status = com_r04_s01__Read_Status();
		buffer[i] = com_r04_s01__Read_FIFO();
	}

	/*** Receiving CRC ***/
	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d1 = com_r04_s01__Read_FIFO();

	while (GPIO_14_GET_VALUE());
	status = com_r04_s01__Read_Status();
	d2 = com_r04_s01__Read_FIFO();

	crc_value_r = (d1 << 8) + d2;
	crc_value_c = crc(buffer, len);

	if (crc_value_r != crc_value_c)
		return COM_R04_S01__ERROR;

//	com_r04_s01__Disable_Receiver();

	return COM_R04_S01__NOERROR;

}

/*********************************************************************/
/*********  CRC  *****************************************************/
/*********************************************************************/

unsigned short CRC_Table[256] = { 0x0000, 0x1189, 0x2312, 0x329B, 0x4624,
		0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5,
		0xE97E, 0xF8F7, 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7,
		0x643E, 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876,
		0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, 0xAD4A,
		0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, 0x3183, 0x200A,
		0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, 0xBDCB, 0xAC42, 0x9ED9,
		0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, 0x4204, 0x538D, 0x6116, 0x709F,
		0x0420, 0x15A9, 0x2732, 0x36BB, 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868,
		0x99E1, 0xAB7A, 0xBAF3, 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528,
		0x37B3, 0x263A, 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB,
		0xAA72, 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9,
		0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, 0x7387,
		0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, 0xFFCF, 0xEE46,
		0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, 0x8408, 0x9581, 0xA71A,
		0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, 0x0840, 0x19C9, 0x2B52, 0x3ADB,
		0x4E64, 0x5FED, 0x6D76, 0x7CFF, 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD,
		0xC324, 0xF1BF, 0xE036, 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C,
		0x7DF7, 0x6C7E, 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C,
		0xD1B5, 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD,
		0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, 0x39C3,
		0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, 0xC60C, 0xD785,
		0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, 0x4A44, 0x5BCD, 0x6956,
		0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, 0xD68D, 0xC704, 0xF59F, 0xE416,
		0x90A9, 0x8120, 0xB3BB, 0xA232, 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1,
		0x0D68, 0x3FF3, 0x2E7A, 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3,
		0x8238, 0x93B1, 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70,
		0x1FF9, 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330,
		0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 };

unsigned short update_crc(unsigned short crc, unsigned char *buf, int len) {
	unsigned short c = crc ^ 0xFFFF;
	int n;

	for (n = 0; n < len; n++) {
		c = CRC_Table[(c ^ buf[n]) & 0xFF] ^ (c >> 8);
	}

	return c ^ 0xFFFF;
}

unsigned short crc(unsigned char *buf, int len) {
	return update_crc(0, buf, len);
}
